#include <asm-generic/socket.h>
#include <func.h>

int main()
{
    //创建服务器的监听套接字
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    ERROR_CHECK(listenfd, -1, "socket");

    //设置套接字的网络地址可以重用
    int on = 1;
    int ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    ERROR_CHECK(ret, -1, "setsockopt");

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    //指定使用的是IPv4的地址类型 AF_INET
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(8080);
    serveraddr.sin_addr.s_addr = inet_addr("192.168.30.129");

    //以人类可阅读的方式打印网络地址
    printf("%s:%d\n", 
           inet_ntoa(serveraddr.sin_addr),
           ntohs(serveraddr.sin_port));

    //绑定服务器的网络地址
    ret = bind(listenfd, (const struct sockaddr*)&serveraddr, 
                   sizeof(serveraddr));
    ERROR_CHECK(ret, -1, "bind");

    //监听客户端的到来
    ret = listen(listenfd, 1);

    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    int peerfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len);
    printf("client %s:%d has connected.\n",
           inet_ntoa(clientaddr.sin_addr),
           ntohs(clientaddr.sin_port));

    fd_set rdset;
    FD_ZERO(&rdset);
    char buff[100] = {0};

    //事件循环
    while(1) {
        FD_SET(STDIN_FILENO, &rdset);
        FD_SET(peerfd, &rdset);
        select(peerfd + 1, &rdset, NULL, NULL, NULL);
        //当select函数返回时，rdset会被修改的

        if(FD_ISSET(STDIN_FILENO, &rdset)) {
            //读取从键盘输入的字符串
            memset(buff, 0, sizeof(buff));
            //通过read函数会把'\n'也读进来
            ret = read(STDIN_FILENO, buff, sizeof(buff));
            if(strcmp(buff, "bye\n") == 0) {
                close(peerfd);
                break;
            }
            //在发送时，不需要发送'\n'
            send(peerfd, buff, ret - 1, 0);
        }

        if(FD_ISSET(peerfd, &rdset)) {
            memset(buff, 0, sizeof(buff));
            //当对端断开之后，使用select监听peerfd的读事件，
            //会一直触发(水平触发)
            ret = recv(peerfd, buff, sizeof(buff), 0);
            if(ret == 0) {
                //recv的返回值为0，说明连接已经断开了
                printf("byebye.\n");
                close(peerfd);
                break;
            }
            printf("ret: %d, recv: %s\n", ret, buff);
        }
    }

    close(listenfd);
    return 0;
}

